#pragma once
#include<iostream>
#include<string>
#include<cstring>
#include<functional>

#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include <sys/wait.h>

#include"Logger.hpp"
#include"Comm.hpp"
#include"InetAddr.hpp"

const int glistendefault=-1;
const uint16_t _port=8888;
const int gbacklog=8;

using callback_t = std::function<std::string(const std::string&)>;

class CommandServer
{
private:
    void HandlerIO(int sockfd, InetAddr client)
    {
        char buffer[1024];
        while(true)
        {
            buffer[0]=0;
            ssize_t n=read(sockfd,buffer,sizeof(buffer)-1);
            if(n>0)
            {
                buffer[n]=0;
                LOG(Loglevel::DEBUG) << client.ToString() << "say: " << buffer;

                std::string result=_cb(buffer);
                write(sockfd, result.c_str(), result.size());
            }
            else if (n == 0)
            {
                LOG(Loglevel::INFO) << "client "
                        << client.ToString() << " quit, me too, close fd: " << sockfd;
                break;
            }
            else
            {
                LOG(Loglevel::WARNING) << "read client "
                    << client.ToString() << " error, sockfd : " << sockfd;
                break;
            }
        }
        close(sockfd); // 一定要关闭
    }
public:
    CommandServer(const uint16_t&port,callback_t cb)
        :_port(port),
        _listenfd(glistendefault),
        _cb(cb)
    {}
    void Init()
    {
        _listenfd=socket(AF_INET,SOCK_STREAM,0);
        if(_listenfd<-1)
        {
            LOG(Loglevel::FATAL) << "create tcp socket error";
            exit(SOCKET_CREAT_ERROR);
        }
        LOG(Loglevel::INFO) << "create tcp socket success "<<_listenfd;

        InetAddr local(_port);

        if(bind(_listenfd,local.Addr(),local.Length())!=0)
        {
            LOG(Loglevel::FATAL) << "bind socket error"<<_listenfd;
            exit(SOCKET_BIND_ERROR);
        }
        LOG(Loglevel::INFO) << "bind socket success";

        if(listen(_listenfd,gbacklog)!=0)
        {
            LOG(Loglevel::FATAL) << "listen socket error";
            exit(SOCKET_LISTEN_ERROR);
        }
        LOG(Loglevel::INFO) << "listen socket success"<<_listenfd;
    }

    class ThreadData
    {
    public:
        ThreadData(int sockfd,CommandServer*tcpserver,InetAddr addr)
            :_sockfd(sockfd),
            _self(tcpserver),
            _addr(addr)
        {}
        ~ThreadData()
        {}
    public:
        int _sockfd;
        CommandServer* _self;
        InetAddr _addr;
    };

    static void *Route(void *args)
    {
        ThreadData *td = static_cast<ThreadData*>(args);
        pthread_detach(pthread_self());
        td->_self->HandlerIO(td->_sockfd, td->_addr);

        return nullptr;
    }

    void Start()
    {
        while(true)
        {
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            int sockfd=accept(_listenfd,(struct sockaddr*)&peer,&len);
            if(sockfd < 0)
            {
                LOG(Loglevel::WARNING) << "accept client error";
                continue;
            }
            InetAddr clientaddr(peer);
            LOG(Loglevel::INFO) << "获取新连接成功, sockfd is : " << sockfd
                                << " client addr: " << clientaddr.ToString();

            
            // version3 多线程做法
            pthread_t tid;
            ThreadData *td=new ThreadData(sockfd,this,clientaddr);
            pthread_create(&tid,nullptr,Route,(void*)td);
        }
    }
    ~CommandServer()
    {}
private:
    int _listenfd;
    uint16_t _port;
    callback_t _cb;
};